package ch04;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class SelectSockets {

	public static int port_number = 1234;

	public static void main(String[] args) throws IOException {
		new SelectSockets().start(args);
	}

	public void start(String[] args) throws IOException{
		int port = port_number;
		if(args.length > 0){
			port = Integer.parseInt(args[0]);
		}

		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		ServerSocket serverSocket = serverSocketChannel.socket();
		serverSocket.bind(new InetSocketAddress(port));
		serverSocketChannel.configureBlocking(false);

		Selector selector = Selector.open();
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

		while(true){
			int n = selector.select();
			if(n == 0){
				continue;
			}

			Iterator<SelectionKey>  iter = selector.selectedKeys().iterator();
			while(iter.hasNext()){
				SelectionKey key = iter.next();
				if(key.isAcceptable()){

					ServerSocketChannel server = (ServerSocketChannel)key.channel();
					SocketChannel channel = server.accept();
					registerChannel(selector,channel,SelectionKey.OP_READ);
					sayHello(channel);
				}

				if(key.isReadable()){
					readDataFromSocket(key);
				}
				iter.remove();
			}
		}
	}

	public ByteBuffer buffer = ByteBuffer.allocate(1024);

	private void readDataFromSocket(SelectionKey key) throws IOException {
		SocketChannel socketChannel = (SocketChannel) key.channel();
		int count;

		buffer.clear();
		while( (count =socketChannel.read(buffer)) > 0){
			buffer.flip();

			while (buffer.hasRemaining()) {
				socketChannel.write(buffer);
			}
			buffer.clear();
		}

		if(count < 0){
			socketChannel.close();
		}
	}

	private void sayHello(SocketChannel channel) throws IOException {
		buffer.clear();
		buffer.put("Hi here! \r\n".getBytes());
		buffer.flip();

		channel.write(buffer);
	}

	private void registerChannel(Selector selector, SocketChannel channel,int ops) throws IOException {
		if(channel == null){
			return;
		}
		channel.configureBlocking(false);
		channel.register(selector, ops);
	}

}
